#!/usr/bin/env ruby

require 'twitter'

class Twitter::Base
	
	# Modify post method to support custom application headers and codes.
	def post(status)
		headers = {
							 "User-Agent" => "#{RedBook::NAME} v#{RedBook::VERSION}",
							 "X-Twitter-Client" => RedBook::NAME,
			         "X-Twitter-Client-Version" => RedBook::VERSION
			        }

		url = URI.parse("http://#{@@api_url}/statuses/update.xml")
		req = Net::HTTP::Post.new(url.path, headers)
		
		req.basic_auth(@config[:email], @config[:password])
		req.set_form_data({'status' => status, 'source' => RedBook::NAME})
		
		response = Net::HTTP.new(url.host, url.port).start { |http| http.request(req) }
		Twitter::Status.new_from_xml(parse(response.body).at('status'))
	end
end

RedBook::Parser.operations = [:user, :timeline, :friends, :followers, :messages]
RedBook::Parser.special_tags = ['_twitter', '_to:']

class RedBook::Logger
	
	# Initialize Twitter Plugin hooks. <i>[Twitter Plugin]</i>
	def initialize_twitter
		@hooks.add :after_start do 
			begin
				@twitter = Twitter::Base.new(@@config[:twitter_username], @@config[:twitter_password])
				notify({:warning => "Twitter credential not specified in rbconfig.yml"}) if @twitter.blank?
			rescue
				raise LoggerError, "Unable to connect to your Twitter account."
			end
		end
		
		@hooks.add :after_log_message do |args|
			if args[:activity][:tags] then
				user_tags = []
				args[:activity][:tags].each do |t|
					user_tags << t if t.match(/_to:([a-zA-Z0-9_]+)/)
				end
				if !user_tags.blank? then
					user_tags.each do |u|
						notify({:info => "Sending Twitter message..."})
						twitter_send(args[:activity][:message], u.scan(/_to:([a-zA-Z0-9_]+)/).to_s)
					end
				elsif args[:activity][:tags].include?("_twitter") then
					notify({:info => "Logging activity to Twitter..."})
					twitter_post args[:activity][:message]
				end
			end
		end
		
		@hooks.add :sort_config_header do |args|
			args[:scfg][:twitter] = {:info => 'Twitter Settings'}
			false
		end
		
		@hooks.add :sort_config_match do |args|
			if args[:index].to_s =~ /^twitter_/ && args[:scfg][:twitter] then
				args[:scfg][:twitter] << { args[:index] => args[:value], :_attributes => {:raw => true}}
				true
			end
		end
	end
		
	# Display the last Twitter status of the specified user (self if no message provided). <i>Twitter Plugin</i>
	#
	# <i>Message Format:</i> <tt><nothing></tt> (default) or <tt>[<twitter_username>]</tt>
	def user
		raise LoggerError, "Twitter credentials unknown" if @twitter.blank?
		tw_user = @command[:message] || @@config[:twitter_username]
		begin
			twitter_user(@twitter.user(tw_user))
		rescue
			raise LoggerError, "Twitter user \"#{tw_user}\" not found."
		end	
	end
	
	# Display the list of Twitter followers. <i>[Twitter Plugin]</i>
	#
	# <i>Message Format:</i> n/a
	def followers
		raise LoggerError, "Twitter credentials unknown" if @twitter.blank?
		notify({:info => "Retrieving followers information..."})
		@twitter.followers.each do |f|
			twitter_user(f)
		end
	end
	
	# Display the list of Twitter friends. <i>[Twitter Plugin]</i>
	#
	# <i>Message Format:</i> n/a
	def friends
		raise LoggerError, "Twitter credentials unknown" if @twitter.blank?
		notify({:info => "Retrieving friends information..."})
		@twitter.friends.each do |f|
			twitter_user(f)
		end
	end
	
	# Display a Twitter timeline. <i>[Twitter Plugin]</i>
	#
	# <i>Message Format:</i> <tt>user</tt> (default) or <tt>friends</tt> or <tt>public</tt>
	def timeline
		raise LoggerError, "Twitter credentials unknown" if @twitter.blank?
		@command[:message] = 'user' unless @command[:message]
		notify({:info => "Retrieving timeline..."})
		tl = @twitter.timeline(@command[:message].to_sym)
		tl.each do |s|
			twitter_message(s)
		end
		notify({:warning => "No data available."}) if tl.blank?
	end

	# Display a list of direct messages. <i>[Twitter Plugin]</i>
	#
	# <i>Message Format:</i> 'in|received' or 'out|sent'
	# <i>Additional Directives:</i>
	# * <tt>:since</tt> - A time expression for the start date
	def messages
		raise LoggerError, "Twitter credentials unknown" if @twitter.blank?
		notify({:info => "Retrieving messages..."})
		case @command[:message]
		when /in|received/ then
			msg = @twitter.received_messages(@command[:from])
		 	msg.each do |s|
				twitter_message(s, 'sender')
			end
			notify({:warning => "There are no received messages."}) if msg.blank?
		when /out|sent/ then
			msg = @twitter.sent_messages(@command[:from])
			msg.each do |s|
				twitter_message(s, 'recipient')
			end
			notify({:warning => "There are no sent messages."}) if msg.blank?
		else
			raise LoggerError, "Please specify whether to display 'sent' or 'received' messages"
		end
	end

	

	private
	
	def twitter_post(msg)
			begin
				@twitter.post(msg)
				notify({:success => "Twitter status changed to \"#{msg}\""})
			rescue
				notify({:warning => "Unable to change Twitter status"})
			end
		end
		
		def twitter_send(msg, u)
			begin
				@twitter.d(u, msg)
				notify({:success => "Message sent to \"#{u}\""})
			rescue
				notify({:warning => "Unable to send message to \"#{u}\""})
			end
		end
		
		def twitter_user(u)
			user = {:user => u.screen_name}
			user[:_attributes] = {}
			user[:_attributes][:real_name] = u.name
			user << {:description => u.description} if u.description
			user << {:location => u.location} if u.location
			user << {:url => u.url} if u.url
			user << {:status => u.status.text} if u.status.text
			user << {:last_update => u.status.created_at.to_time} if u.status.created_at
			notify(user)
		end
		
		def twitter_message(s, user_type=nil)
			username = (user_type) ? "#{user_type}_screen_name" : "user.name"
			screen_name = instance_eval("s.#{username}")
			activity = {:activity => nil, :_attributes => {:message => s.text}}
			activity << {:start_time =>  s.created_at.to_time}
			activity << {:tag => screen_name }
			notify(activity)
		end
	
end
